

#ifndef _TSOC_RAYTRACER_
#define _TSOC_RAYTRACER_

#include <vector>
#include <stdint.h>
#include <pthread.h>

#include "Scene.hpp"
#include "Graph.hpp"
#include "Photon.hpp"
#include "Math.hpp"
#include "Color.hpp"



namespace com
{
	namespace toxiclabs
	{
		namespace tsoc
		{
			
			class Chunk
			{
				public:
					int x;
					int y;
					int w;
					int h;
			};
			
			class HitPoint
			{
				public:
							
					
					Vector position;
					Vector normal;
					Color direct;
				
					Vector uvw;
					Triangle * triangle;
					
					float N;
					float radius;
					Color flux;
					
					HitPoint * next;
			};
			
						
			class RayTracer
			{
				protected:
								
					int num_threads;
					
					uint32_t * buffer;
					float * zbuffer;
					
					std::vector<Chunk *> chunks;
					HitPoint ** hits;
					
					pthread_mutex_t mutex_getchunk;
					pthread_mutex_t mutex_commitchunk;
					
					Scene * scene;
					Graph * graph;
					
					PhotonMap photon_map;
					int num_photons;
					int photons_per_surface;
					int emitted_photons;
					int total_emitted_photons;
					float ppm_radius;
					int ppm_min_bounce;
					
					int direct_light_samples;
										
					bool shader_ao;
					int shader_ao_n;
					float shader_ao_factor;
					
					std::vector<Triangle * > emitters;
					
					Random * random;
										
					
				public:
				
					int width;
					int height;
					float fov;
					Vector camera_pos;
					
					
				
				RayTracer(int width,int height,int threads,Scene * scene,Graph * graph);
				virtual ~RayTracer();
				
				void CreateChunks();
				Chunk * GetChunk();
				
				virtual void CommitChunk(Chunk * chunk);
				void Irradiate();
				virtual void Render();
				void Gather();
				void Compose();
				void ComposeThread(int id);
				void IrradiateThread(int id);
				void RenderThread(int id);
				void PostProcess(Chunk * chunk);
				void PhotonCast(Vector &origin,Vector &direction,Color &power,int bounce,std::vector<Photon *> * photons);
				HitPoint * RayCast(Vector &origin,Vector &direction);
				void GetLightContribution(Triangle * tri,Vector &position,Vector &normal,Color * power);
				Vector GetUVW(Triangle * tri,Vector &collision);
				Vector PerturbateNormal(Triangle * tri,float angle,float r1,float r2);
				Vector PerturbateNormal(Triangle * tri,float angle);
				void PutPixel(int x,int y,uint32_t pixel,float depth);
				
				void TGADump(const char * filename);
			};
			
		}
	}
}


#endif
